package modelo;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Random;

import excepciones.TableroIndiceFueraDeRangoExcepcion;
	
import modelo.GeneradorDeEscenarios;

public class GeneradorDeEscenariosReal extends GeneradorDeEscenarios {
	
	private List<Class<? extends Direccion>> clasesDeDirecciones = new ArrayList<Class<? extends Direccion>>();
	private Random random = new Random();
	
	@Override
	public Collection<Barco> generarEscenario(Tablero tablero) {
		// Agrega todas las direcciones posibles en la lista clasesDePosiciones.
		cargarDirecciones();
		
		Collection<Barco> barcos = new ArrayList<Barco>();
		
		// Agrega los barcos necesarios a la coleccion.
		barcos.add(crearBarco(Lancha.class, tablero));
		barcos.add(crearBarco(Lancha.class, tablero));
		
		barcos.add(crearBarco(Destructor.class, tablero));
		barcos.add(crearBarco(Destructor.class, tablero));
		
		barcos.add(crearBarco(Buque.class, tablero));
		
		barcos.add(crearBarco(RompeHielos.class, tablero));
		
		barcos.add(crearBarco(Portaaviones.class, tablero));
		
		return barcos;
	}
	
	private void cargarDirecciones() {
		clasesDeDirecciones.add(Norte.class);
		clasesDeDirecciones.add(Sur.class);
		clasesDeDirecciones.add(Este.class);
		clasesDeDirecciones.add(Oeste.class);
		clasesDeDirecciones.add(Noreste.class);
		clasesDeDirecciones.add(Noroeste.class);
		clasesDeDirecciones.add(Sureste.class);
		clasesDeDirecciones.add(Suroeste.class);
		
		Collections.shuffle(clasesDeDirecciones);
	}
	
	private Direccion getDireccion() {
		int indice = random.nextInt(clasesDeDirecciones.size());
		Direccion direccion = null;
		
		try {
			direccion = clasesDeDirecciones.get(indice).newInstance();
		}
		catch (InstantiationException | IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return direccion;
	}
	
	private List<Posicion> getPosiciones(Tablero tablero, int cantidadDePosiciones) {
		List<Posicion> posiciones = new ArrayList<Posicion>();
		int filaInicial = random.nextInt(tablero.getCantidadDeFilas());
		int columnaInicial = random.nextInt(tablero.getCantidadDeColumnas());
		
		Posicion posicion = null;
		
		// Obtiene la posicion inicial en forma aleatoria y la agrega a la lista posiciones.
		try {
			posicion = tablero.getPosicion(filaInicial, columnaInicial);
		}
		catch (TableroIndiceFueraDeRangoExcepcion e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		posiciones.add(posicion);
		
		// Si la posicion final se encuentra dentro del tablero agrega a la lista
		// posiciones todas las posiciones intermedias.
		
		// Vertical superior
		if (tablero.posicionValida(filaInicial - cantidadDePosiciones + 1, columnaInicial)) {
			for (int i = 1; i < cantidadDePosiciones; i++) {
				try {
					posiciones.add(tablero.getPosicion(filaInicial - i, columnaInicial));
				}
				catch (TableroIndiceFueraDeRangoExcepcion e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}	
		}
		// Horizontal derecha.
		else if (tablero.posicionValida(filaInicial, columnaInicial + cantidadDePosiciones - 1)) {
			for (int i = 1; i < cantidadDePosiciones; i++) {
				try {
					posiciones.add(tablero.getPosicion(filaInicial, columnaInicial + i));
				}
				catch (TableroIndiceFueraDeRangoExcepcion e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		// Vertical inferior.
		else if (tablero.posicionValida(filaInicial + cantidadDePosiciones - 1, columnaInicial)) {
			for (int i = 1; i < cantidadDePosiciones; i++) {
				try {
					posiciones.add(tablero.getPosicion(filaInicial + i, columnaInicial));
				}
				catch (TableroIndiceFueraDeRangoExcepcion e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		// Horizontal izquierda.
		else if (tablero.posicionValida(filaInicial, columnaInicial - cantidadDePosiciones + 1)) {
			for (int i = 1; i < cantidadDePosiciones; i++) {
				try {
					posiciones.add(tablero.getPosicion(filaInicial, columnaInicial - i));
				}
				catch (TableroIndiceFueraDeRangoExcepcion e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		return posiciones;
	}
	
	private Barco crearBarco(Class<? extends Barco> claseDeBarco, Tablero tablero) {
		List<Posicion> posiciones = null;
		Barco barco = null;
		int tamanio = 0;
		
		// Obtiene una direccion en forma aleatoria. 
		Direccion direccion = getDireccion();
		
		// Obtiene el tamaño del barco.
		if (claseDeBarco == Buque.class) {
			tamanio = Buque.getTamanio();
		}
		else if (claseDeBarco == Destructor.class) {
			tamanio = Destructor.getTamanio();
		}
		else if (claseDeBarco == Lancha.class) {
			tamanio = Lancha.getTamanio();
		}
		else if (claseDeBarco == Portaaviones.class) {
			tamanio = Portaaviones.getTamanio();
		}
		else if (claseDeBarco == RompeHielos.class) {
			tamanio = RompeHielos.getTamanio();
		}
		
		// Obtiene la cantidad de posiciones necesarias para el barco.
		posiciones = getPosiciones(tablero, tamanio);
		
		// Crea el barco correspondiente.
		try {
			barco = claseDeBarco.asSubclass(Barco.class).getConstructor(List.class, Direccion.class).newInstance(posiciones, direccion);
		}
		catch (InstantiationException | IllegalAccessException
				| IllegalArgumentException | InvocationTargetException
				| NoSuchMethodException | SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return barco;
	}
}